package org.vison.wonfu.framework.soa.protocol.jsonRpc;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.core5.http.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vison.wonfu.framework.soa.exception.RpcException;
import org.vison.wonfu.framework.soa.protocol.AbstractParamsHandler;
import org.vison.wonfu.framework.soa.Invocation;
import org.vison.wonfu.framework.soa.protocol.InvocationParamsHandler;
import org.vison.wonfu.framework.soa.protocol.Protocol;

import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URL;
import java.util.concurrent.ThreadLocalRandom;

import static org.vison.wonfu.framework.soa.protocol.jsonRpc.JsonRpcConstants.*;

/**
 * <a href="https://wiki.geekdream.com/Specification/json-rpc_2.0.html">什么是json-rpc 协议？</a>
 */
@InvocationParamsHandler(protocol = Protocol.JSON_RPC)
public class JsonRpcParamsHandler extends AbstractParamsHandler {

    private final static Logger log = LoggerFactory.getLogger(JsonRpcParamsHandler.class);

    private static final ContentType CONTENT_TYPE = ContentType.create("application/json-rpc", "UTF-8");


    @Override
    protected SimpleHttpRequest doPack(Invocation invocation, String uri, Object[] argument) throws RpcException {
        ObjectMapper objectMapper = getContextObjectMapper(invocation);
        ObjectNode jsonrpc = new ObjectNode(objectMapper.getNodeFactory());
        jsonrpc.put(ID, Integer.toString(ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE)));
        jsonrpc.put(METHOD, invocation.getMethodName());
        jsonrpc.put(JSONRPC, VERSION);
        jsonrpc.set(PARAMS, arrayParams(objectMapper,  argument));
        byte[] bytes = null;
        try {
            bytes = objectMapper.writeValueAsBytes(jsonrpc);
        } catch (JsonProcessingException e) {
            throw new RpcException(RpcException.SERIALIZATION_EXCEPTION, "json rpc pack error", e);
        }
        return SimpleRequestBuilder.post(uri).setBody(bytes, CONTENT_TYPE).build();
    }

    private ArrayNode arrayParams(ObjectMapper mapper, Object[] args) {
        ArrayNode params = new ArrayNode(mapper.getNodeFactory());
        for (Object arg : args) {
            params.add(mapper.valueToTree(arg));
        }
        return params;
    }

    @Override
    public Object resolveBody(String responseBody, Type returnGenericType, ObjectMapper objectMapper) throws IOException {
        JsonRpcResponse jsonRpcResponse = objectMapper.readValue(responseBody, JsonRpcResponse.class);
        if (jsonRpcResponse.getError() != null) {
            throw new RpcException(RpcException.UNKNOWN_EXCEPTION, jsonRpcResponse.getError().getMessage());
        }
        Object needUnpackBody =  jsonRpcResponse.getResult();
        String needUnpackBodyStr = objectMapper.writeValueAsString(needUnpackBody);
        return  super.resolveBody(needUnpackBodyStr,returnGenericType,objectMapper);
    }
}
